/**
 * 
 */
package GUI.network;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;

import officeserver.log_error.AppointmentException;
import officeserver.log_error.OfficeException;
import officeserver.log_error.UserException;
import officeserver.office.OfficeInterface;
import officeserver.office.request.AdminRequest;
import officeserver.office.request.AdminRequest.TYPE;
import officeserver.office.request.AppointmentRequest;
import officeserver.office.request.AppointmentSelfRequest;
import officeserver.office.request.RequestException;
import officeserver.office.request.UserRequest;
import officeserver.office.request.UserSelfRequest;
import officeserver.report.Appointment;
import officeserver.users.AccessLevel;
import officeserver.users.PersonalInfo;

/**
 * @author Chris Bayruns
 * 
 */
public class OfficeConnection implements OfficeInterface {
    GUI.network.NetworkConnection netCon = null;
    /**
     * @author Chris Bayruns
     * @param host
     *            The host to connect to
     * @param port
     *            The port to connect to
     * @throws UnknownHostException
     * @throws IOException
     */
    private String host;
    private int port;

    public OfficeConnection(String host, int port) throws UnknownHostException,
	    IOException {
	this.host = host;
	this.port = port;
	connect();
    }

    /**
     * @author Chris Bayruns
     * @return If the network is connected
     */
    public boolean isConnected() {
	return netCon.isConnected();
    }

    /**
     * @author Chris Bayruns Connect to the server
     * @throws IOException
     * @throws UnknownHostException
     */
    public void connect() throws UnknownHostException, IOException {
	netCon = new GUI.network.NetworkConnection(host, port);
    }

    public void disconnect() throws IOException {
	netCon.disconnect();
    }

    /**
     * This logs in a user.
     * 
     * @author Chris Bayruns
     * @param username
     *            The username to log int to.
     * @param password
     *            The password
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws UserException
     * @throws RequestException
     */
    public boolean userLogin(String username, String password)
	    throws IOException, ClassNotFoundException, UserException,
	    RequestException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_LOGIN, username, password));
	testUserException(temp.getError());
	testRequestException(temp.getError());

	return temp.getError() != null;
    }

    /**
     * Logs the user out.
     * 
     * @author Chris Bayruns
     * @throws Exception
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void userLogout() throws Exception {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_LOGOUT));
	testException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @return Whether you are logged in
     * @throws Exception
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public boolean isLoggedIn() throws Exception {
	boolean result = false;

	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.IS_LOGGED_IN));
	testException(temp.getError());
	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (Boolean) temp.getData()[0];
	}

	return result;
    }

    /**
     * Adds a user
     * 
     * @author Chris Bayruns
     * @param firstName
     *            The first name
     * @param lastName
     *            The last name
     * @param username
     *            The username
     * @param password
     *            The password
     * @param accessLevel
     *            The access level
     * @throws UserException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public void addUser(String firstName, String lastName, String username,
	    String password, AccessLevel accessLevel) throws UserException,
	    IOException, ClassNotFoundException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_ADD, firstName, lastName, username,
		password, accessLevel));
	testUserException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param id
     *            The id to search for
     * @param level
     *            The level to search in
     * @throws ClassNotFoundException
     * @throws IOException
     * @throws UserException
     */
    public void userSearch(int id, AccessLevel level) throws UserException,
	    IOException, ClassNotFoundException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_SEARCH, id, level));
	testUserException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param username
     *            The username to search for
     * @throws ClassNotFoundException
     * @throws IOException
     * @throws UserException
     */
    public void userSearch(String username) throws IOException,
	    ClassNotFoundException, UserException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_SEARCH, username));
	testUserException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param firstName
     *            The first name to search for
     * @param lastName
     *            The last name to search for
     * @throws ClassNotFoundException
     * @throws IOException
     * @throws UserException
     */
    public void userSearch(String firstName, String lastName)
	    throws IOException, ClassNotFoundException, UserException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_SEARCH, firstName, lastName));
	testUserException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param info
     *            The info to set
     * @throws IOException
     * @throws ClassNotFoundException
     * @throws UserException
     */
    public void setSelfPersonalInfo(PersonalInfo info) throws IOException,
	    ClassNotFoundException, UserException {
	UserRequest temp = (UserSelfRequest) netCon
		.request(new UserSelfRequest(UserRequest.TYPE.SET_USER_INFO,
			info));
	testUserException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @return The personal info object associated with your account
     * @throws UserException
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public PersonalInfo getSelfPersonalInfo() throws UserException,
	    IOException, ClassNotFoundException {
	PersonalInfo result = null;
	UserRequest temp = (UserSelfRequest) netCon
		.request(new UserSelfRequest(UserRequest.TYPE.USER_INFO));
	testUserException(temp.getError());

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (PersonalInfo) temp.getData()[0];
	}

	return result;
    }

    /**
     * @author Chris Bayruns
     * @return The personal info of the user searched for
     * @throws UserException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public PersonalInfo getSearchPersonalInfo() throws UserException,
	    IOException, ClassNotFoundException {
	PersonalInfo result = null;
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_INFO));
	testUserException(temp.getError());

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (PersonalInfo) temp.getData()[0];
	}

	return result;
    }

    /**
     * @author Chris Bayruns
     * @param info
     *            Sets the personal info of the searched user
     * @throws UserException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public void setSearchPersonalInfo(PersonalInfo info) throws UserException,
	    IOException, ClassNotFoundException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_INFO, info));
	testUserException(temp.getError());
    }

    /**
     * Deletes a user
     * 
     * @author Chris Bayruns
     * @throws UserException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public void deleteSearchUser() throws UserException, IOException,
	    ClassNotFoundException {
	UserRequest temp = (UserRequest) netCon.request(new UserRequest(
		UserRequest.TYPE.USER_REMOVE));
	testUserException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @return An arraylist of the patients appointments
     * @throws UserException
     * @throws AppointmentException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public ArrayList<Appointment> getSelfAppointments() throws UserException,
	    AppointmentException, IOException, ClassNotFoundException {
	ArrayList<Appointment> result = null;
	AppointmentSelfRequest temp = (AppointmentSelfRequest) netCon
		.request(new AppointmentSelfRequest(
			AppointmentSelfRequest.TYPE.USER_APPOINTMENTS));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (ArrayList<Appointment>) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }
    
    /**
     * @author Chris Bayruns
     * @return An arraylist of the patients appointments
     * @throws UserException
     * @throws AppointmentException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public Appointment getSelfAppointments(int index) throws UserException,
	    AppointmentException, IOException, ClassNotFoundException {
	Appointment result = null;
	AppointmentSelfRequest temp = (AppointmentSelfRequest) netCon
		.request(new AppointmentSelfRequest(
			AppointmentSelfRequest.TYPE.USER_APPOINTMENTS, index));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (Appointment) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }
    
    @Override
    public Integer getSelfUserNumAppointments() throws UserException, IOException, ClassNotFoundException, AppointmentException {
	Integer result = null;
	AppointmentRequest temp = (AppointmentSelfRequest) netCon
		.request(new AppointmentSelfRequest(
			AppointmentSelfRequest.TYPE.USER_NUM_APPOINTMENTS));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (Integer) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }
    /**
     * @author Chris Bayruns
     * @return An an appointment
     * @throws UserException
     * @throws AppointmentException 
     * @throws ClassNotFoundException 
     * @throws IOException 
     */
    public Appointment getSearchUserAppointments(int index)
	    throws UserException, AppointmentException, IOException, ClassNotFoundException {
	Appointment result = null;
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.USER_APPOINTMENTS, index));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (Appointment) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }
    /**
     * @author Chris Bayruns
     * @return An arraylist of the patients appointments
     * @throws UserException
     * @throws AppointmentException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public ArrayList<Appointment> getSearchUserAppointments()
	    throws UserException, AppointmentException, IOException,
	    ClassNotFoundException {
	ArrayList<Appointment> result = null;
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.USER_APPOINTMENTS));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (ArrayList<Appointment>) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }
    @Override
    public Integer getSearchUserNumAppointments() throws UserException, IOException, ClassNotFoundException, AppointmentException {
	Integer result = null;
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.USER_NUM_APPOINTMENTS));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (Integer) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }
    /**
     * @author Chris Bayruns
     * @param docID
     *            The doctor you want
     * @param day
     *            The day you want
     * @param timeSlot
     *            The timeslot you want
     * @throws ClassNotFoundException
     * @throws IOException
     * @throws UserException
     * @throws AppointmentException
     * @throws Exception
     */
    public void addSelfAppointment(int docID, int day, int timeSlot)
	    throws IOException, ClassNotFoundException, UserException,
	    AppointmentException {
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.REQUEST_APPOINTMENT, docID,
			day, timeSlot));
	testUserException(temp.getError());
	testAppointmentException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param day
     *            The day to search
     * @return The avaliablity of dat
     * @throws Exception
     */
    public boolean[][] selfCheckCalendar(int day) throws Exception {
	boolean[][] result = null;
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.CHECK_CALENDER_FREE, day));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (boolean[][]) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }

    /**
     * @author Chris Bayruns
     * @return The arraylist of the appointments
     * @throws UserException
     * @throws ClassNotFoundException
     * @throws IOException
     * @throws AppointmentException
     * @throws Exception
     */
    public ArrayList<Appointment> getWaitingAppointments()
	    throws UserException, IOException, ClassNotFoundException,
	    AppointmentException {
	ArrayList<Appointment> result = null;
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.GET_WAITING_APPOINTMENTS));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (ArrayList<Appointment>) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }

    /**
     * @author Chris Bayruns
     * @throws UserException
     * @throws AppointmentException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public void confirmSearchUserAppointment(Appointment confirm)
	    throws UserException, AppointmentException, IOException,
	    ClassNotFoundException {
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.CONFIRM_APPOINTMENT, confirm));
	testUserException(temp.getError());
	testAppointmentException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param update
     *            The appointment to update
     * @throws Exception
     */
    public void updateSearchUserAppointment(Appointment update)
	    throws Exception {
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.UPDATE_APPOINTMENT, update));
	testUserException(temp.getError());
	testAppointmentException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param update
     *            The appointment to update
     * @throws Exception
     */
    /*
     * public void updateSelfUserAppointment(Appointment update) throws
     * Exception{ AppointmentRequest temp = (AppointmentRequest)
     * netCon.request(new AppointmentRequest(
     * AppointmentRequest.TYPE.UPDATE_APPOINTMENT, update));
     * testUserException(temp.getError());
     * testAppointmentException(temp.getError()); }
     */

    /**
     * @author Chris Bayruns
     * @param day
     *            The day to get appointments on
     * @return The arraylist of the appointments
     * @throws Exception
     */
    public ArrayList<Appointment> getAppointmentsByDay(int day)
	    throws Exception {
	ArrayList<Appointment> result = null;
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.GET_APPOINTMENTS_BY_DAY, day));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (ArrayList<Appointment>) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }

    /**
     * @author Chris Bayruns
     * @param delete
     *            The appointment to delete
     * @throws Exception
     */
    public void deleteSearchUserAppointment(Appointment delete)
	    throws Exception {
	AppointmentRequest temp = (AppointmentRequest) netCon
		.request(new AppointmentRequest(
			AppointmentRequest.TYPE.DELETE_APPOINTMENT, delete));
	testUserException(temp.getError());
	testAppointmentException(temp.getError());
    }

    @Override
    public void load() throws IOException, ClassNotFoundException,
	    OfficeException {
	AdminRequest temp = null;
	temp = (AdminRequest) netCon.request(new AdminRequest(TYPE.LOAD));

	testUserException(temp.getError());
	testAppointmentException(temp.getError());
	testOfficeException(temp.getError());
    }

    @Override
    public void save() throws IOException, ClassNotFoundException,
	    OfficeException {
	AdminRequest temp = null;
	temp = (AdminRequest) netCon.request(new AdminRequest(TYPE.SAVE));

	testUserException(temp.getError());
	testAppointmentException(temp.getError());
	testOfficeException(temp.getError());
    }

    /**
     * @author Chris Bayruns
     * @param e
     *            The exception to test
     * @throws Exception
     */
    private void testException(Exception e) throws Exception {
	if (e != null) {
	    throw (e);
	}
    }

    /**
     * @author Chris Bayruns
     * @param e
     *            The exception to test
     * @throws Exception
     */
    private void testUserException(Exception e) throws UserException {
	if (e != null && e instanceof UserException) {
	    throw ((UserException) e);
	}
    }

    /**
     * @author Chris Bayruns
     * @param e
     *            The exception to test
     * @throws UserException
     * @throws Exception
     */
    private void testAppointmentException(Exception e)
	    throws AppointmentException {
	if (e != null && e instanceof AppointmentException) {
	    throw ((AppointmentException) e);
	}
    }

    /**
     * @author Chris Bayruns
     * @param e
     *            The exception to test
     * @throws UserException
     * @throws Exception
     */
    private void testOfficeException(Exception e) throws OfficeException {
	if (e != null && e instanceof OfficeException) {
	    throw ((OfficeException) e);
	}
    }

    /**
     * @author Chris Bayruns
     * @param e
     *            The exception to test
     * @throws Exception
     */
    private void testRequestException(Exception e) throws RequestException {
	if (e != null && e instanceof UserException) {
	    throw ((RequestException) e);
	}
    }

    @Override
    public ArrayList<PersonalInfo> getAllUsers() throws UserException, IOException, ClassNotFoundException, AppointmentException {
	ArrayList<PersonalInfo> result = null;
	UserRequest temp = (UserRequest) netCon
		.request(new UserRequest(
			UserRequest.TYPE.GET_ALL_USERS));

	if (temp != null && temp.getData() != null && temp.getData().length > 0) {
	    result = (ArrayList<PersonalInfo>) temp.getData()[0];
	}
	testUserException(temp.getError());
	testAppointmentException(temp.getError());

	return result;
    }

	@Override
	public ArrayList<PersonalInfo> getActivePatients() throws UserException, IOException, ClassNotFoundException, AppointmentException
	{
		ArrayList<PersonalInfo> result = null;
		UserRequest temp = (UserRequest) netCon
			.request(new UserRequest(
				UserRequest.TYPE.GET_ACTIVE_PATIENTS));

		if (temp != null && temp.getData() != null && temp.getData().length > 0) {
		    result = (ArrayList<PersonalInfo>) temp.getData()[0];
		}
		testUserException(temp.getError());
		testAppointmentException(temp.getError());
		return result;
	}

	@Override
	public ArrayList<PersonalInfo> getDoctors() throws UserException, IOException, ClassNotFoundException, AppointmentException
	{
		ArrayList<PersonalInfo> result = null;
		UserRequest temp = (UserRequest) netCon
			.request(new UserRequest(
				UserRequest.TYPE.GET_DOCS));

		if (temp != null && temp.getData() != null && temp.getData().length > 0) {
		    result = (ArrayList<PersonalInfo>) temp.getData()[0];
		}
		testUserException(temp.getError());
		testAppointmentException(temp.getError());
		return result;
	}


}
